/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib.experiments;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.NullMod;
import ac.jp.u_tokyo.SyncLib.PrimMod;
import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SynchronizationFailedException;
import ac.jp.u_tokyo.SyncLib.dictionaries.DictMod;
import ac.jp.u_tokyo.SyncLib.dictionaries.DictModFactory;
import ac.jp.u_tokyo.SyncLib.experiments.generated.EJB;
import ac.jp.u_tokyo.SyncLib.experiments.generated.EJBOptimized;
import ac.jp.u_tokyo.SyncLib.language3.GlobalIncrementalFactory;

public class EJBExperiment
{
	protected DictMod createObjectMod(Object... paras)
	{
		DictModFactory result = new DictModFactory();
		for (int i = 0; i < paras.length / 2; i++)
		{
			if (paras[i * 2 + 1] == null)
				result.addRemove(paras[i * 2]);
			else
				result.addPut(paras[i * 2], new PrimMod(paras[i * 2 + 1]));
		}
		return result.create();
	}

	Set<Integer> entitybeanIDs = new HashSet<Integer>();

	Random r = new Random();

	Sync fillEntityBeans(int size) throws SynchronizationFailedException
	{
		Sync sync = EJB.getmainFactory().create();
		DictModFactory<Integer, Map<String, Object>> ejbMod = new DictModFactory<Integer, Map<String, Object>>();
		DictModFactory<Integer, Map<String, String>> moduleMod = new DictModFactory<Integer, Map<String, String>>();
		int moduleID = 0;
		for (int i = 0; i < size; i++)
		{
			if (i % 10 == 0)
			{
				moduleID = new GlobalIncrementalFactory().createNewKey();
				moduleMod.addPut(moduleID, createObjectMod("Name", "module"
						+ r.nextInt(1000)));
				moduleMod.addPut(moduleID, createObjectMod("Description",
						"some description:" + r.nextInt()));

			}
			ejbMod.addPut(new GlobalIncrementalFactory().createNewKey(),
					createObjectMod("Module", moduleID, "Name", "ejb"
							+ r.nextInt(), "Persistent", r.nextBoolean()));
		}
		beforeSynchronization = System.currentTimeMillis();
		Mod[] result = sync.synchronize(new Mod[] { ejbMod.create(),
				moduleMod.create(), NullMod.INSTANCE });
		entitybeanIDs.clear();
		entitybeanIDs.addAll(((DictMod) result[2]).getKeys());
		afterSynchronization = System.currentTimeMillis();
		System.out.println("Created " + size + " pairs: "
				+ (afterSynchronization - beforeSynchronization));
		return sync;
	}

	long beforeSynchronization;

	long afterSynchronization;

	Sync modifyEJBName(Sync sync, int size)
			throws SynchronizationFailedException
	{
		DictModFactory<Integer, Map<String, String>> mod = new DictModFactory<Integer, Map<String, String>>();
		Iterator<Integer> it = entitybeanIDs.iterator();
		for (int i = 0; i < size; i++)
		{
			mod.addPut(it.next(), createObjectMod("EJBName", "newEJBName"
					+ r.nextInt()));
		}
		return invokeWithTimeRecorded(sync, NullMod.INSTANCE, NullMod.INSTANCE,
				mod.create());
	}

	Sync addEntityBean(Sync sync, int size)
			throws SynchronizationFailedException
	{
		DictModFactory<Integer, Map<String, String>> mod = new DictModFactory<Integer, Map<String, String>>();
		for (int i = 0; i < size; i++)
		{
			Integer newID = new GlobalIncrementalFactory().createNewKey();
			mod.addPut(newID, createObjectMod("EJBName", "newEJBName"
					+ r.nextInt()));
			mod.addPut(newID, createObjectMod("ModuleName", "module"
					+ r.nextInt(1000)));
		}
		DictMod<Integer, Map<String, String>> dictMod = mod.create();
//		System.out.println(dictMod);
		return invokeWithTimeRecorded(sync, NullMod.INSTANCE, NullMod.INSTANCE,
				dictMod);
	}

	Sync removeEntityBean(Sync sync, int size)
			throws SynchronizationFailedException
	{
		DictModFactory<Integer, Map<String, String>> mod = new DictModFactory<Integer, Map<String, String>>();
		Iterator<Integer> it = entitybeanIDs.iterator();
		for (int i = 0; i < size; i++)
		{
			mod.addPut(it.next(), PrimMod.NULL);
		}
		return invokeWithTimeRecorded(sync, NullMod.INSTANCE, NullMod.INSTANCE,
				mod.create());
	}

	private Sync invokeWithTimeRecorded(Sync sync, Mod ejbs, Mod modules,
			Mod entitybeans) throws SynchronizationFailedException
	{
		beforeSynchronization = System.currentTimeMillis();
		Mod[] result = sync
				.synchronize(new Mod[] { ejbs, modules, entitybeans });
//		System.out.println(Arrays.toString(result));
		afterSynchronization = System.currentTimeMillis();
		return sync;
	}

	void report(int modSize, final int size)
			throws SynchronizationFailedException
	{
		System.gc();
		Sync sync = fillEntityBeans(size);
		System.gc();
		modifyEJBName(sync, modSize);
		System.out.println("Modifying \"EntityBean.Name\". Mod Size: "
				+ modSize + " EJB Count: " + size + " Time(in milliseconds): "
				+ (afterSynchronization - beforeSynchronization));
		System.gc();
		removeEntityBean(sync, modSize);
		System.out.println("Removing \"EntityBean\". Mod Size: " + modSize
				+ " EJB Count: " + size + " Time(in milliseconds): "
				+ (afterSynchronization - beforeSynchronization));
		System.gc();
		addEntityBean(sync, modSize);
		System.out.println("Adding \"EntityBean\". Mod Size: " + modSize
				+ " EJB Count: " + size + " Time(in milliseconds): "
				+ (afterSynchronization - beforeSynchronization));
		System.gc();
	}

	public static void main(String[] args)
			throws SynchronizationFailedException
	{
		EJBExperiment exp = new EJBExperiment();
		exp.report(5, 500);
		exp.report(5, 1000);
		exp.report(5, 1500);
		exp.report(5, 2000);
		exp.report(5, 2500);
		exp.report(5, 3000);
	}
}
